package cn.sylinx.common.ext.reflect;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.beanutils.BeanUtils;

import cn.sylinx.common.ext.exception.WrappedException;
import cn.sylinx.common.ext.log.GLog;

@SuppressWarnings("unchecked")
public final class ReflectUtil {

	public static final void copyProperties(Object src, Object dest) {

		try {
			BeanUtils.copyProperties(dest, src);
		} catch (IllegalAccessException e) {
			GLog.error("error: ", e);
		} catch (InvocationTargetException e) {
			GLog.error("error: ", e);
		}
	}

	public static final <T> T cloneBean(T bean) {

		try {
			return (T) BeanUtils.cloneBean(bean);
		} catch (IllegalAccessException e) {
			GLog.error("error: ", e);
		} catch (InvocationTargetException e) {
			GLog.error("error: ", e);
		} catch (InstantiationException e) {
			GLog.error("error: ", e);
		} catch (NoSuchMethodException e) {
			GLog.error("error: ", e);
		}

		return null;
	}

	public static final Map<String, Object> toMap(Object bean) {
		Map<String, Object> returnMap = new HashMap<String, Object>();
		Field[] fields = bean.getClass().getDeclaredFields();
		try {
			for (Field field : fields) {
				field.setAccessible(true);
				returnMap.put(field.getName(), field.get(bean));
			}
		} catch (IllegalArgumentException e) {
			GLog.error("error: ", e);
		} catch (IllegalAccessException e) {
			GLog.error("error: ", e);
		}

		return returnMap;
	}

	public static final <T> T toObject(Map<String, Object> map, Class<T> clz) {

		T t = newInstance(clz);
		List<Field> fieldList = getObjectAllFields(clz);
		for (Field item : fieldList) {
			set(item, t, map.get(item.getName()));
		}
		return t;
	}

	public static List<Field> getObjectAllFields(Class<?> cclz) {

		List<Field> fields = new ArrayList<Field>();
		Field[] fs = cclz.getDeclaredFields();
		if (fs != null && fs.length > 0) {
			for (Field f : fs) {

				String modifiers = Modifier.toString(f.getModifiers());
				if (!modifiers.contains("final") && !modifiers.contains("static")) {
					fields.add(f);
				}
			}
		}

		Class<?> pclz = cclz.getSuperclass();
		if (pclz != null && !pclz.isInterface()) {

			List<Field> fds1 = getObjectAllFields(pclz);
			if (fds1 != null && !fds1.isEmpty()) {
				fields.addAll(fds1);
			}
		}

		return fields;

	}

	public static Map<String, Field> getObjectAllFieldsMap(Class<?> cclz) {
		Map<String, Field> fields = new HashMap<String, Field>();
		Field[] fs = cclz.getDeclaredFields();
		if (fs != null && fs.length > 0) {
			for (Field f : fs) {
				String modifiers = Modifier.toString(f.getModifiers());
				if (!modifiers.contains("final") && !modifiers.contains("static")) {
					fields.put(f.getName(), f);
				}
			}
		}
		Class<?> pclz = cclz.getSuperclass();
		if (pclz != null && !pclz.isInterface()) {
			Map<String, Field> fds1 = getObjectAllFieldsMap(pclz);
			if (fds1 != null && !fds1.isEmpty()) {
				fields.putAll(fds1);
			}
		}
		return fields;
	}

	public static <T> T newInstance(Class<T> clz) {

		if (clz == null) {
			throw new NullPointerException("clz cannot be null");
		}

		T t = null;
		try {
			t = clz.newInstance();
		} catch (InstantiationException e) {
			GLog.error("error:", e);
			throw new WrappedException(e);
		} catch (IllegalAccessException e) {
			GLog.error("error:", e);
			throw new WrappedException(e);
		}

		return t;
	}

	/**
	 * 设置对象值
	 * 
	 * @param f
	 * @param object
	 * @param value
	 */
	public static void set(Field f, Object object, Object value) {

		f.setAccessible(true);
		try {
			f.set(object, value);
		} catch (IllegalArgumentException e) {
			GLog.error("error:", e);
			throw new WrappedException(e);
		} catch (IllegalAccessException e) {
			GLog.error("error:", e);
			throw new WrappedException(e);
		}
	}

	public static Object get(Field f, Object object) {

		f.setAccessible(true);
		try {
			return f.get(object);
		} catch (IllegalArgumentException e) {
			GLog.error("error:", e);
			throw new WrappedException(e);
		} catch (IllegalAccessException e) {
			GLog.error("error:", e);
			throw new WrappedException(e);
		}
	}
}
